home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 1 Issue 2 / PDCD-1 - Issue 02.iso / _utilities / utilities / 001 / fue / c / EXEC < prev    next >
Text File  |  1991-04-03  |  43KB  |  1,349 lines

  1. /*      This file is for functions dealing with execution of
  2.         commands, command lines, buffers, files and startup files
  3.  
  4.         written 1986 by Daniel Lawrence                         */
  5.  
  6. /*      Modifications:
  7.         11-Sep-89       Mike Burrow (INMOS)     Added folding.
  8. */
  9.  
  10. #include        <stdio.h>
  11. #include        "estruct.h"
  12. #include        "etype.h"
  13. #include        "edef.h"
  14. #include        "elang.h"
  15.  
  16. /* namedcmd:    execute a named command even if it is not bound */
  17.  
  18. PASCAL NEAR namedcmd(f, n)
  19.  
  20. int f, n;       /* command arguments [passed through to command executed] */
  21.  
  22. {
  23.         int (PASCAL NEAR *kfunc)();     /* ptr to the function to execute */
  24.         char buffer[NSTRING];           /* buffer to store function name */
  25.         int status;
  26.  
  27.         /* if we are non-interactive.... force the command interactivly */
  28.         if (clexec == TRUE) {
  29.                 /* grab token and advance past */
  30.                 execstr = token(execstr, buffer, NPAT);
  31.  
  32.                 /* evaluate it */
  33.                 strcpy(buffer, fixnull(getval(buffer)));
  34.                 if (strcmp(buffer, errorm) == 0)
  35.                         return(FALSE);
  36.  
  37.                 /* and look it up */
  38.                 if ((kfunc = fncmatch(buffer)) == NULL) {
  39.                         mlwrite(TEXT16);
  40. /*                              "[No such Function]" */
  41.                         return(FALSE);
  42.                 }
  43.                 
  44.                 /* and execute it  INTERACTIVE */
  45.                 clexec = FALSE;
  46.                 status = (*kfunc)(f, n);        /* call the function */
  47.                 clexec = TRUE;
  48.                 return(status);
  49.         }
  50.  
  51.         /* prompt the user to type a named command */
  52.         /* and get the function name to execute */
  53.         kfunc = getname(": ");
  54.         if (kfunc == NULL) {
  55.                 mlwrite(TEXT16);
  56. /*                      "[No such function]" */
  57.                 return(FALSE);
  58.         }
  59.  
  60.         /* and then execute the command */
  61.         return((*kfunc)(f, n));
  62. }
  63.  
  64. /*      execcmd:        Execute a command line command to be typed in
  65.                         by the user                                     */
  66.  
  67. PASCAL NEAR execcmd(f, n)
  68.  
  69. int f, n;       /* default Flag and Numeric argument */
  70.  
  71. {
  72.         register int status;            /* status return */
  73.         char cmdstr[NSTRING];           /* string holding command to execute */
  74.  
  75.         /* get the line wanted */
  76.         if ((status = mlreply(": ", cmdstr, NSTRING)) != TRUE)
  77.                 return(status);
  78.  
  79.         execlevel = 0;
  80.         return(docmd(cmdstr));
  81. }
  82.  
  83. /*      docmd:  take a passed string as a command line and translate
  84.                 it to be executed as a command. This function will be
  85.                 used by execute-command-line and by all source and
  86.                 startup files. Lastflag/thisflag is also updated.
  87.  
  88.         format of the command line is:
  89.  
  90.                 {# arg} <command-name> {<argument string(s)>}
  91.  
  92. */
  93.  
  94. PASCAL NEAR docmd(cline)
  95.  
  96. char *cline;    /* command line to execute */
  97.  
  98. {
  99.         register int f;         /* default argument flag */
  100.         register int n;         /* numeric repeat value */
  101.         int (PASCAL NEAR *fnc)();/* function to execute */
  102.         BUFFER *bp;             /* buffer to execute */
  103.         int status;             /* return status of function */
  104.         int oldcle;             /* old contents of clexec flag */
  105.         char *oldestr;          /* original exec string */
  106.         char tkn[NSTRING];      /* next token off of command line */
  107.         char bufn[NBUFN+2];     /* name of buffer to execute */
  108.  
  109.         /* if we are scanning and not executing..go back here */
  110.         if (execlevel)
  111.                 return(TRUE);
  112.  
  113.         oldestr = execstr;      /* save last ptr to string to execute */
  114.         execstr = cline;        /* and set this one as current */
  115.  
  116.         /* first set up the default command values */
  117.         f = FALSE;
  118.         n = 1;
  119.         lastflag = thisflag;
  120.         thisflag = 0;
  121.  
  122.         if ((status = macarg(tkn)) != TRUE) {   /* and grab the first token */
  123.                 execstr = oldestr;
  124.                 return(status);
  125.         }
  126.  
  127.         /* process leadin argument */
  128.         if (gettyp(tkn) != TKCMD) {
  129.                 f = TRUE;
  130.                 strcpy(tkn, fixnull(getval(tkn)));
  131.                 n = asc_int(tkn);
  132.  
  133.                 /* and now get the command to execute */
  134.                 if ((status = macarg(tkn)) != TRUE) {
  135.                         execstr = oldestr;
  136.                         return(status);
  137.                 }
  138.         }
  139.  
  140.         /* and match the token to see if it exists */
  141.         if ((fnc = fncmatch(tkn)) == NULL) {
  142.  
  143.                 /* construct the buffer name */
  144.                 strcpy(bufn, "[");
  145.                 strcat(bufn, tkn);
  146.                 strcat(bufn, "]");
  147.  
  148.                 /* find the pointer to that buffer */
  149.                 if ((bp=bfind(bufn, FALSE, 0)) == NULL) {
  150.                         mlwrite(TEXT16);
  151. /*                            "[No such Function]" */
  152.                         execstr = oldestr;
  153.                         return(FALSE);
  154.                 }
  155.  
  156.                 /* execute the buffer */
  157.                 oldcle = clexec;        /* save old clexec flag */
  158.                 clexec = TRUE;          /* in cline execution */
  159.                 while (n-- > 0)
  160.                         if ((status = dobuf(bp)) != TRUE)
  161.                                 break;
  162.                 cmdstatus = status;     /* save the status */
  163.                 clexec = oldcle;        /* restore clexec flag */
  164.                 execstr = oldestr;
  165.                 return(status);
  166.         }
  167.         
  168.         /* save the arguments and go execute the command */
  169.         oldcle = clexec;                /* save old clexec flag */
  170.         clexec = TRUE;                  /* in cline execution */
  171.         status = (*fnc)(f, n);          /* call the function */
  172.         cmdstatus = status;             /* save the status */
  173.         clexec = oldcle;                /* restore clexec flag */
  174.         execstr = oldestr;
  175.         return(status);
  176. }
  177.  
  178. /* token:       chop a token off a string
  179.                 return a pointer past the token
  180. */
  181.  
  182. char *PASCAL NEAR token(src, tok, size)
  183.  
  184. char *src, *tok;        /* source string, destination token string */
  185. int size;               /* maximum size of token */
  186.  
  187. {
  188.         register int quotef;    /* is the current string quoted? */
  189.         register char c;        /* temporary character */
  190.  
  191.         /* first scan past any whitespace in the source string */
  192.         while (*src == ' ' || *src == '\t')
  193.                 ++src;
  194.  
  195.         /* scan through the source string */
  196.         quotef = FALSE;
  197.         while (*src) {
  198.                 /* process special characters */
  199.                 if (*src == '~') {
  200.                         ++src;
  201.                         if (*src == 0)
  202.                                 break;
  203.                         switch (*src++) {
  204.                                 case 'r':       c = 13; break;
  205.                                 case 'n':       c = 13; break;
  206.                                 case 'l':       c = 10; break;
  207.                                 case 't':       c = 9;  break;
  208.                                 case 'b':       c = 8;  break;
  209.                                 case 'f':       c = 12; break;
  210.                                 default:        c = *(src-1);
  211.                         }
  212.                         if (--size > 0) {
  213.                                 *tok++ = c;
  214.                         }
  215.                 } else {
  216.                         /* check for the end of the token */
  217.                         if (quotef) {
  218.                                 if (*src == '"')
  219.                                         break;
  220.                         } else {
  221.                                 if (*src == ' ' || *src == '\t')
  222.                                         break;
  223.                         }
  224.  
  225.                         /* set quote mode if quote found */
  226.                         if (*src == '"')
  227.                                 quotef = TRUE;
  228.  
  229.                         /* record the character */
  230.                         c = *src++;
  231.                         if (--size > 0)
  232.                                 *tok++ = c;
  233.                 }
  234.         }
  235.  
  236.         /* terminate the token and exit */
  237.         if (*src)
  238.                 ++src;
  239.         *tok = 0;
  240.         return(src);
  241. }
  242.  
  243. PASCAL NEAR macarg(tok) /* get a macro line argument */
  244.  
  245. char *tok;      /* buffer to place argument */
  246.  
  247. {
  248.         int savcle;     /* buffer to store original clexec */
  249.         int status;
  250.  
  251.         savcle = clexec;        /* save execution mode */
  252.         clexec = TRUE;          /* get the argument */
  253.         status = nextarg("", tok, NSTRING, ctoec('\r'));
  254.         clexec = savcle;        /* restore execution mode */
  255.         return(status);
  256. }
  257.  
  258. /*      nextarg:        get the next argument   */
  259.  
  260. PASCAL NEAR nextarg(prompt, buffer, size, terminator)
  261.  
  262. char *prompt;           /* prompt to use if we must be interactive */
  263. char *buffer;           /* buffer to put token into */
  264. int size;               /* size of the buffer */
  265. int terminator;         /* terminating char to be used on interactive fetch */
  266.  
  267. {
  268.         register char *sp;      /* return pointer from getval() */
  269.  
  270.         /* if we are interactive, go get it! */
  271.         if (clexec == FALSE)
  272.                 return(getstring(prompt, buffer, size, terminator));
  273.  
  274.         /* grab token and advance past */
  275.         execstr = token(execstr, buffer, size);
  276.  
  277.         /* evaluate it */
  278.         if ((sp = getval(buffer)) == NULL)
  279.                 return(FALSE);
  280.         strcpy(buffer, sp);
  281.         return(TRUE);
  282. }
  283.  
  284. /*      storemac:       Set up a macro buffer and flag to store all
  285.                         executed command lines there                    */
  286.  
  287. PASCAL NEAR storemac(f, n)
  288.  
  289. int f;          /* default flag */
  290. int n;          /* macro number to use */
  291.  
  292. {
  293.         register struct BUFFER *bp;     /* pointer to macro buffer */
  294.         char bname[NBUFN];              /* name of buffer to use */
  295.  
  296.         /* must have a numeric argument to this function */
  297.         if (f == FALSE) {
  298.                 mlwrite(TEXT111);
  299. /*                      "No macro specified" */
  300.                 return(FALSE);
  301.         }
  302.  
  303.         /* range check the macro number */
  304.         if (n < 1 || n > 40) {
  305.                 mlwrite(TEXT112);
  306. /*                      "Macro number out of range" */
  307.                 return(FALSE);
  308.         }
  309.  
  310.         /* construct the macro buffer name */
  311.         strcpy(bname, "[Macro xx]");
  312.         bname[7] = '0' + (n / 10);
  313.         bname[8] = '0' + (n % 10);
  314.  
  315.         /* set up the new macro buffer */
  316.         if ((bp = bfind(bname, TRUE, BFINVS)) == NULL) {
  317.                 mlwrite(TEXT113);
  318. /*                      "Can not create macro" */
  319.                 return(FALSE);
  320.         }
  321.  
  322.         /* and make sure it is empty */
  323.         bclear(bp);
  324.  
  325.         /* and set the macro store pointers to it */
  326.         mstore = TRUE;
  327.         bstore = bp;
  328.         return(TRUE);
  329. }
  330.  
  331. #if     PROC
  332. /*      storeproc:      Set up a procedure buffer and flag to store all
  333.                         executed command lines there                    */
  334.  
  335. PASCAL NEAR storeproc(f, n)
  336.  
  337. int f;          /* default flag */
  338. int n;          /* macro number to use */
  339.  
  340. {
  341.         register struct BUFFER *bp;     /* pointer to macro buffer */
  342.         register int status;            /* return status */
  343.         char bname[NBUFN];              /* name of buffer to use */
  344.  
  345.         /* a numeric argument means its a numbered macro */
  346.         if (f == TRUE)
  347.                 return(storemac(f, n));
  348.  
  349.         /* get the name of the procedure */
  350.         if ((status = mlreply(TEXT114, &bname[1], NBUFN-2)) != TRUE)
  351. /*                            "Procedure name: " */
  352.                 return(status);
  353.  
  354.         /* construct the macro buffer name */
  355.         bname[0] = '[';
  356.         strcat(bname, "]");
  357.  
  358.         /* set up the new macro buffer */
  359.         if ((bp = bfind(bname, TRUE, BFINVS)) == NULL) {
  360.                 mlwrite(TEXT113);
  361. /*                      "Can not create macro" */
  362.                 return(FALSE);
  363.         }
  364.  
  365.         /* and make sure it is empty */
  366.         bclear(bp);
  367.  
  368.         /* and set the macro store pointers to it */
  369.         mstore = TRUE;
  370.         bstore = bp;
  371.         return(TRUE);
  372. }
  373.  
  374. /*      execproc:       Execute a procedure                             */
  375.  
  376. PASCAL NEAR execproc(f, n)
  377.  
  378. int f, n;       /* default flag and numeric arg */
  379.  
  380. {
  381.         register BUFFER *bp;            /* ptr to buffer to execute */
  382.         register int status;            /* status return */
  383.         char bufn[NBUFN+2];             /* name of buffer to execute */
  384.  
  385.         /* find out what buffer the user wants to execute */
  386.         if ((status = mlreply(TEXT115, &bufn[1], NBUFN)) != TRUE)
  387. /*                            "Execute procedure: " */
  388.                 return(status);
  389.  
  390.         /* construct the buffer name */
  391.         bufn[0] = '[';
  392.         strcat(bufn, "]");
  393.  
  394.         /* find the pointer to that buffer */
  395.         if ((bp=bfind(bufn, FALSE, 0)) == NULL) {
  396.                 mlwrite(TEXT116);
  397. /*                      "No such procedure" */
  398.                 return(FALSE);
  399.         }
  400.  
  401.         /* and now execute it as asked */
  402.         while (n-- > 0)
  403.                 if ((status = dobuf(bp)) != TRUE)
  404.                         return(status);
  405.         return(TRUE);
  406. }
  407. #endif
  408.  
  409. /*      execbuf:        Execute the contents of a buffer of commands    */
  410.  
  411. PASCAL NEAR execbuf(f, n)
  412.  
  413. int f, n;       /* default flag and numeric arg */
  414.  
  415. {
  416.         register BUFFER *bp;            /* ptr to buffer to execute */
  417.         register int status;            /* status return */
  418.         char bufn[NSTRING];             /* name of buffer to execute */
  419.  
  420.         /* find out what buffer the user wants to execute */
  421.         if ((status = mlreply(TEXT117, bufn, NBUFN)) != TRUE)
  422. /*                            "Execute buffer: " */
  423.                 return(status);
  424.  
  425.         /* find the pointer to that buffer */
  426.         if ((bp=bfind(bufn, FALSE, 0)) == NULL) {
  427.                 mlwrite(TEXT118);
  428. /*                      "No such buffer" */
  429.                 return(FALSE);
  430.         }
  431.  
  432.         /* and now execute it as asked */
  433.         while (n-- > 0)
  434.                 if ((status = dobuf(bp)) != TRUE)
  435.                         return(status);
  436.         return(TRUE);
  437. }
  438.  
  439. /*      dobuf:  execute the contents of the buffer pointed to
  440.                 by the passed BP
  441.  
  442.         Directives start with a "!" and include:
  443.  
  444.         !endm           End a macro
  445.         !if (cond)      conditional execution
  446.         !else
  447.         !endif
  448.         !return         Return (terminating current macro)
  449.         !goto <label>   Jump to a label in the current macro
  450.         !force          Force macro to continue...even if command fails
  451.         !while (cond)   Execute a loop if the condition is true
  452.         !endwhile
  453.         
  454.         Line Labels begin with a "*" as the first nonblank char, like:
  455.  
  456.         *LBL01
  457. */
  458.  
  459. PASCAL NEAR dobuf(bp)
  460.  
  461. BUFFER *bp;     /* buffer to execute */
  462.  
  463. {
  464.         register int status;    /* status return */
  465.         register LINE *lp;      /* pointer to line to execute */
  466.         register LINE *hlp;     /* pointer to line header */
  467.         register LINE *glp;     /* line to goto */
  468.         LINE *mp;               /* Macro line storage temp */
  469.         int dirnum;             /* directive index */
  470.         int linlen;             /* length of line to execute */
  471.         int i;                  /* index */
  472.         int force;              /* force TRUE result? */
  473.         WINDOW *wp;             /* ptr to windows to scan */
  474.         WHBLOCK *whlist;        /* ptr to !WHILE list */
  475.         WHBLOCK *scanner;       /* ptr during scan */
  476.         WHBLOCK *whtemp;        /* temporary ptr to a WHBLOCK */
  477.         char *einit;            /* initial value of eline */
  478.         char *eline;            /* text of line to execute */
  479.         char tkn[NSTRING];      /* buffer to evaluate an expresion in */
  480. #if     LOGFLG
  481.         FILE *fp;               /* file handle for log file */
  482. #endif
  483.  
  484.         /* clear IF level flags/while ptr */
  485.         execlevel = 0;
  486.         whlist = NULL;
  487.         scanner = NULL;
  488.  
  489.         /* scan the buffer to execute, building WHILE header blocks */
  490.         hlp = bp->b_linep;
  491.         lp = hlp->l_fp;
  492.         while (lp != hlp) {
  493.                 /* scan the current line */
  494.                 eline = lp->l_text;
  495.                 i = lp->l_used;
  496.  
  497.                 /* trim leading whitespace */
  498.                 while (i-- > 0 && (*eline == ' ' || *eline == '\t'))
  499.                         ++eline;
  500.  
  501.                 /* if theres nothing here, don't bother */
  502.                 if (i <= 0)
  503.                         goto nxtscan;
  504.  
  505.                 /* if is a while directive, make a block... */
  506.                 if (eline[0] == '!' && eline[1] == 'w' && eline[2] == 'h') {
  507.                         whtemp = (WHBLOCK *)malloc(sizeof(WHBLOCK));
  508.                         if (whtemp == NULL) {
  509. noram:                          mlwrite(TEXT119);
  510. /*                                      "%%Out of memory during while scan" */
  511. failexit:                       freewhile(scanner);
  512.                                 freewhile(whlist);
  513.                                 return(FALSE);
  514.                         }
  515.                         whtemp->w_begin = lp;
  516.                         whtemp->w_type = BTWHILE;
  517.                         whtemp->w_next = scanner;
  518.                         scanner = whtemp;
  519.                 }
  520.  
  521.                 /* if is a BREAK directive, make a block... */
  522.                 if (eline[0] == '!' && eline[1] == 'b' && eline[2] == 'r') {
  523.                         if (scanner == NULL) {
  524.                                 mlwrite(TEXT120);
  525. /*                                      "%%!BREAK outside of any !WHILE loop" */
  526.                                 goto failexit;
  527.                         }
  528.                         whtemp = (WHBLOCK *)malloc(sizeof(WHBLOCK));
  529.                         if (whtemp == NULL)
  530.                                 goto noram;
  531.                         whtemp->w_begin = lp;
  532.                         whtemp->w_type = BTBREAK;
  533.                         whtemp->w_next = scanner;
  534.                         scanner = whtemp;
  535.                 }
  536.  
  537.                 /* if it is an endwhile directive, record the spot... */
  538.                 if (eline[0] == '!' && strncmp(&eline[1], "endw", 4) == 0) {
  539.                         if (scanner == NULL) {
  540.                                 mlwrite(TEXT121,
  541. /*                                      "%%!ENDWHILE with no preceding !WHILE in '%s'" */
  542.                                         bp->b_bname);
  543.                                 goto failexit;
  544.                         }
  545.                         /* move top records from the scanner list to the
  546.                            whlist until we have moved all BREAK records
  547.                            and one WHILE record */
  548.                         do {
  549.                                 scanner->w_end = lp;
  550.                                 whtemp = whlist;
  551.                                 whlist = scanner;
  552.                                 scanner = scanner->w_next;
  553.                                 whlist->w_next = whtemp;
  554.                         } while (whlist->w_type == BTBREAK);
  555.                 }
  556.  
  557. nxtscan:        /* on to the next line */
  558.                 lp = lp->l_fp;
  559.         }
  560.  
  561.         /* while and endwhile should match! */
  562.         if (scanner != NULL) {
  563.                 mlwrite(TEXT122,
  564. /*                      "%%!WHILE with no matching !ENDWHILE in '%s'" */
  565.                         bp->b_bname);
  566.                 goto failexit;
  567.         }
  568.  
  569.         /* let the first command inherit the flags from the last one..*/
  570.         thisflag = lastflag;
  571.  
  572.         /* starting at the beginning of the buffer */
  573.         hlp = bp->b_linep;
  574.         lp = hlp->l_fp;
  575.         while (lp != hlp && eexitflag == FALSE) {
  576.                 /* allocate eline and copy macro line to it */
  577.                 linlen = lp->l_used;
  578.                 if ((einit = eline = malloc(linlen+1)) == NULL) {
  579.                         mlwrite(TEXT123);
  580. /*                              "%%Out of Memory during macro execution" */
  581.                         freewhile(whlist);
  582.                         return(FALSE);
  583.                 }
  584.                 bytecopy(eline, lp->l_text, linlen);
  585.                 eline[linlen] = 0;      /* make sure it ends */
  586.  
  587.                 /* trim leading whitespace */
  588.                 while (*eline == ' ' || *eline == '\t')
  589.                         ++eline;
  590.  
  591.                 /* dump comments and blank lines */
  592.                 if (*eline == ';' || *eline == 0)
  593.                         goto onward;
  594.  
  595. #if     LOGFLG
  596.                 /* append the current command to the log file */
  597.                 fp = fopen("emacs.log", "a");
  598.                 strcpy(outline, eline);
  599.                 fprintf(fp, "%s\n", outline);
  600.                 fclose(fp);
  601. #endif
  602.         
  603. #if     DEBUGM
  604.                 /* only do this if we are debugging */
  605.                 if (macbug && !mstore && (execlevel == 0))
  606.                         if (debug(bp, eline) == FALSE) {
  607.                                 mlforce(TEXT54);
  608. /*                                      "[Macro aborted]" */
  609.                                 freewhile(whlist);
  610.                                 return(FALSE);
  611.                         }
  612. #endif
  613.  
  614.                 /* Parse directives here.... */
  615.                 dirnum = -1;
  616.                 if (*eline == '!') {
  617.                         /* Find out which directive this is */
  618.                         ++eline;
  619.                         for (dirnum = 0; dirnum < NUMDIRS; dirnum++)
  620.                                 if (strncmp(eline, dname[dirnum],
  621.                                             strlen(dname[dirnum])) == 0)
  622.                                         break;
  623.  
  624.                         /* and bitch if it's illegal */
  625.                         if (dirnum == NUMDIRS) {
  626.                                 mlwrite(TEXT124);
  627. /*                                      "%%Unknown Directive" */
  628.                                 freewhile(whlist);
  629.                                 return(FALSE);
  630.                         }
  631.  
  632.                         /* service only the !ENDM macro here */
  633.                         if (dirnum == DENDM) {
  634.                                 mstore = FALSE;
  635.                                 bstore = NULL;
  636.                                 goto onward;
  637.                         }
  638.  
  639.                         /* restore the original eline....*/
  640.                         --eline;
  641.                 }
  642.  
  643.                 /* if macro store is on, just salt this away */
  644.                 if (mstore) {
  645.                         /* allocate the space for the line */
  646.                         linlen = strlen(eline);
  647.                         if ((mp=lalloc(linlen)) == NULL) {
  648.                                 mlwrite(TEXT125);
  649. /*                                      "Out of memory while storing macro" */
  650.                                 return (FALSE);
  651.                         }
  652.  
  653.                         lp->l_type = LNORMAL;           /* MJB: 11-Sep-89 */
  654.                         lp->l_foldp = (LINE *)NULL;     /* MJB: 11-Sep-89 */
  655.                         /* copy the text into the new line */
  656.                         for (i=0; i<linlen; ++i)
  657.                                 lputc(mp, i, eline[i]);
  658.         
  659.                         /* attach the line to the end of the buffer */
  660.                         bstore->b_linep->l_bp->l_fp = mp;
  661.                         mp->l_bp = bstore->b_linep->l_bp;
  662.                         bstore->b_linep->l_bp = mp;
  663.                         mp->l_fp = bstore->b_linep;
  664.                         goto onward;
  665.                 }
  666.         
  667.                 force = FALSE;
  668.  
  669.                 /* dump comments */
  670.                 if (*eline == '*')
  671.                         goto onward;
  672.  
  673.                 /* now, execute directives */
  674.                 if (dirnum != -1) {
  675.                         /* skip past the directive */
  676.                         while (*eline && *eline != ' ' && *eline != '\t')
  677.                                 ++eline;
  678.                         execstr = eline;
  679.  
  680.                         switch (dirnum) {
  681.                         case DIF:       /* IF directive */
  682.                                 /* grab the value of the logical exp */
  683.                                 if (execlevel == 0) {
  684.                                         if (macarg(tkn) != TRUE)
  685.                                                 goto eexec;
  686.                                         if (stol(tkn) == FALSE)
  687.                                                 ++execlevel;
  688.                                 } else
  689.                                         ++execlevel;
  690.                                 goto onward;
  691.  
  692.                         case DWHILE:    /* WHILE directive */
  693.                                 /* grab the value of the logical exp */
  694.                                 if (execlevel == 0) {
  695.                                         if (macarg(tkn) != TRUE)
  696.                                                 goto eexec;
  697.                                         if (stol(tkn) == TRUE)
  698.                                                 goto onward;
  699.                                 }
  700.                                 /* drop down and act just like !BREAK */
  701.  
  702.                         case DBREAK:    /* BREAK directive */
  703.                                 if (dirnum == DBREAK && execlevel)
  704.                                         goto onward;
  705.  
  706.                                 /* jump down to the endwhile */
  707.                                 /* find the right while loop */
  708.                                 whtemp = whlist;
  709.                                 while (whtemp) {
  710.                                         if (whtemp->w_begin == lp)
  711.                                                 break;
  712.                                         whtemp = whtemp->w_next;
  713.                                 }
  714.                         
  715.                                 if (whtemp == NULL) {
  716.                                         mlwrite(TEXT126);
  717. /*                                              "%%Internal While loop error" */
  718.                                         freewhile(whlist);
  719.                                         return(FALSE);
  720.                                 }
  721.                         
  722.                                 /* reset the line pointer back.. */
  723.                                 lp = whtemp->w_end;
  724.                                 goto onward;
  725.  
  726.                         case DELSE:     /* ELSE directive */
  727.                                 if (execlevel == 1)
  728.                                         --execlevel;
  729.                                 else if (execlevel == 0 )
  730.                                         ++execlevel;
  731.                                 goto onward;
  732.  
  733.                         case DENDIF:    /* ENDIF directive */
  734.                                 if (execlevel)
  735.                                         --execlevel;
  736.                                 goto onward;
  737.  
  738.                         case DGOTO:     /* GOTO directive */
  739.                                 /* .....only if we are currently executing */
  740.                                 if (execlevel == 0) {
  741.  
  742.                                         /* grab label to jump to */
  743.                                         eline = token(eline, golabel, NPAT);
  744.                                         linlen = strlen(golabel);
  745.                                         glp = hlp->l_fp;
  746.                                         while (glp != hlp) {
  747.                                                 if (*glp->l_text == '*' &&
  748.                                                     (strncmp(&glp->l_text[1], golabel,
  749.                                                             linlen) == 0)) {
  750.                                                         lp = glp;
  751.                                                         goto onward;
  752.                                                 }
  753.                                                 glp = glp->l_fp;
  754.                                         }
  755.                                         mlwrite(TEXT127);
  756. /*                                              "%%No such label" */
  757.                                         freewhile(whlist);
  758.                                         return(FALSE);
  759.                                 }
  760.                                 goto onward;
  761.         
  762.                         case DRETURN:   /* RETURN directive */
  763.                                 if (execlevel == 0)
  764.                                         goto eexec;
  765.                                 goto onward;
  766.  
  767.                         case DENDWHILE: /* ENDWHILE directive */
  768.                                 if (execlevel) {
  769.                                         --execlevel;
  770.                                         goto onward;
  771.                                 } else {
  772.                                         /* find the right while loop */
  773.                                         whtemp = whlist;
  774.                                         while (whtemp) {
  775.                                                 if (whtemp->w_type == BTWHILE &&
  776.                                                     whtemp->w_end == lp)
  777.                                                         break;
  778.                                                 whtemp = whtemp->w_next;
  779.                                         }
  780.                 
  781.                                         if (whtemp == NULL) {
  782.                                                 mlwrite(TEXT126);
  783. /*                                                      "%%Internal While loop error" */
  784.                                                 freewhile(whlist);
  785.                                                 return(FALSE);
  786.                                         }
  787.                 
  788.                                         /* reset the line pointer back.. */
  789.                                         lp = whtemp->w_begin->l_bp;
  790.                                         goto onward;
  791.                                 }
  792.  
  793.                         case DFORCE:    /* FORCE directive */
  794.                                 force = TRUE;
  795.  
  796.                         }
  797.                 }
  798.  
  799.                 /* execute the statement */
  800.                 status = docmd(eline);
  801.                 if (force)              /* force the status */
  802.                         status = TRUE;
  803.  
  804.                 /* check for a command error */
  805.                 if (status != TRUE) {
  806.                         /* look if buffer is showing */
  807.                         wp = wheadp;
  808.                         while (wp != NULL) {
  809.                                 if (wp->w_bufp == bp) {
  810.                                         /* and point it */
  811.                                         wp->w_dotp = lp;
  812.                                         wp->w_doto = 0;
  813.                                         wp->w_flag |= WFHARD;
  814.                                 }
  815.                                 wp = wp->w_wndp;
  816.                         }
  817.                         /* in any case set the buffer . */
  818.                         bp->b_dotp = lp;
  819.                         bp->b_doto = 0;
  820.                         free(einit);
  821.                         execlevel = 0;
  822.                         freewhile(whlist);
  823.                         return(status);
  824.                 }
  825.  
  826. onward:         /* on to the next line */
  827.                 free(einit);
  828.                 lp = lp->l_fp;
  829.         }
  830.  
  831. eexec:  /* exit the current function */
  832.         execlevel = 0;
  833.         freewhile(whlist);
  834.         return(TRUE);
  835. }
  836.  
  837. #if     DEBUGM
  838. /*              Interactive debugger
  839.  
  840.                 if $debug == TRUE, The interactive debugger is invoked
  841.                 commands are listed out with the ? key                  */
  842.  
  843. PASCAL NEAR debug(bp, eline)
  844.  
  845. BUFFER *bp;     /* buffer to execute */
  846. char *eline;    /* text of line to debug */
  847.  
  848. {
  849.         register int oldcmd;            /* original command display flag */
  850.         register int oldinp;            /* original connamd input flag */
  851.         register int oldstatus;         /* status of last command */
  852.         register int c;                 /* temp character */
  853.         register KEYTAB *key;           /* ptr to a key entry */
  854.         static char track[NSTRING] = "";/* expression to track value of */
  855.         char temp[NSTRING];             /* command or expression */
  856.  
  857. dbuild: /* Build the information line to be presented to the user */
  858.  
  859.         strcpy(outline, "<<<");
  860.  
  861.         /* display the tracked expression */
  862.         if (track[0] != 0) {
  863.                 oldstatus = cmdstatus;
  864.                 docmd(track);
  865.                 cmdstatus = oldstatus;
  866.                 strcat(outline, "[=");
  867.                 strcat(outline, gtusr("track"));
  868.                 strcat(outline, "]");
  869.         }
  870.  
  871.         /* debug macro name */
  872.         strcat(outline, bp->b_bname);
  873.         strcat(outline, ":");
  874.  
  875.         /* and lastly the line */
  876.         strcat(outline, eline);
  877.         strcat(outline, ">>>");
  878.  
  879.         /* expand the %'s so mlwrite() won't interpret them */
  880.         makelit(outline);
  881.  
  882.         /* write out the debug line */
  883. dinput: outline[term.t_ncol - 1] = 0;
  884.         mlforce(outline);
  885.         update(TRUE);
  886.  
  887.         /* and get the keystroke */
  888.         c = getkey();
  889.  
  890.         /* META key turns off debugging */
  891.         key = getbind(c);
  892.         if (key && key->k_ptr.fp == meta)
  893.                 macbug = FALSE;
  894.  
  895.         else if (c == abortc) {
  896.                 return(FALSE);
  897.  
  898.         } else switch (c) {
  899.  
  900.                 case '?': /* list commands */
  901.                         strcpy(outline, TEXT128);
  902. /*"(e)val exp, (c/x)ommand, (t)rack exp, (^G)abort, <SP>exec, <META> stop debug"*/
  903.                         goto dinput;
  904.  
  905.                 case 'c': /* execute statement */
  906.                         oldcmd = discmd;
  907.                         discmd = TRUE;
  908.                         oldinp = disinp;
  909.                         disinp = TRUE;
  910.                         execcmd(FALSE, 1);
  911.                         discmd = oldcmd;
  912.                         disinp = oldinp;
  913.                         goto dbuild;
  914.  
  915.                 case 'x': /* execute extended command */
  916.                         oldcmd = discmd;
  917.                         discmd = TRUE;
  918.                         oldinp = disinp;
  919.                         disinp = TRUE;
  920.                         oldstatus = cmdstatus;
  921.                         namedcmd(FALSE, 1);
  922.                         cmdstatus = oldstatus;
  923.                         discmd = oldcmd;
  924.                         disinp = oldinp;
  925.                         goto dbuild;
  926.  
  927.                 case 'e': /* evaluate expresion */
  928.                         strcpy(temp, "set %track ");
  929.                         oldcmd = discmd;
  930.                         discmd = TRUE;
  931.                         oldinp = disinp;
  932.                         disinp = TRUE;
  933.                         getstring("Exp: ", &temp[11], NSTRING, ctoec('\r'));
  934.                         discmd = oldcmd;
  935.                         disinp = oldinp;
  936.                         oldstatus = cmdstatus;
  937.                         docmd(temp);
  938.                         cmdstatus = oldstatus;
  939.                         strcpy(temp, " = [");
  940.                         strcat(temp, gtusr("track"));
  941.                         strcat(temp, "]");
  942.                         mlforce(temp);
  943.                         c = getkey();
  944.                         goto dinput;
  945.  
  946.                 case 't': /* track expresion */
  947.                         oldcmd = discmd;
  948.                         discmd = TRUE;
  949.                         oldinp = disinp;
  950.                         disinp = TRUE;
  951.                         getstring("Exp: ", temp, NSTRING, ctoec('\r'));
  952.                         discmd = oldcmd;
  953.                         disinp = oldinp;
  954.                         strcpy(track, "set %track ");
  955.                         strcat(track, temp);
  956.                         goto dbuild;
  957.  
  958.                 case ' ': /* execute a statement */
  959.                         break;
  960.  
  961.                 default: /* illegal command */
  962.                         TTbeep();
  963.                         goto dbuild;
  964.         }
  965.         return(TRUE);
  966. }
  967. #endif
  968.  
  969. PASCAL NEAR makelit(s)          /* expand all "%" to "%%" */
  970.  
  971. char *s;        /* string to expand */
  972.  
  973. {
  974.         register char *sp;      /* temp for expanding string */
  975.         register char *ep;      /* ptr to end of string to expand */
  976.  
  977.         sp = s;
  978.         while (*sp)
  979.         if (*sp++ == '%') {
  980.                 /* advance to the end */
  981.                 ep = --sp;
  982.                 while (*ep++)
  983.                         ;
  984.                 /* null terminate the string one out */
  985.                 *(ep + 1) = 0;
  986.                 /* copy backwards */
  987.                 while(ep-- > sp)
  988.                         *(ep + 1) = *ep;
  989.  
  990.                 /* and advance sp past the new % */
  991.                 sp += 2;                                        
  992.         }
  993. }
  994.  
  995. PASCAL NEAR freewhile(wp)       /* free a list of while block pointers */
  996.  
  997. WHBLOCK *wp;    /* head of structure to free */
  998.  
  999. {
  1000.         if (wp != NULL)
  1001.         {
  1002.                 freewhile(wp->w_next);
  1003.                 free(wp);
  1004.         }
  1005. }
  1006.  
  1007. PASCAL NEAR execfile(f, n)      /* execute a series of commands in a file */
  1008.  
  1009. int f, n;       /* default flag and numeric arg to pass on to file */
  1010.  
  1011. {
  1012.         register int status;    /* return status of name query */
  1013.         char *fname;            /* name of file to execute */
  1014.         char *fspec;            /* full file spec */
  1015.  
  1016.         if ((fname = gtfilename(TEXT129)) == NULL)
  1017. /*                              "File to execute" */
  1018.                 return(FALSE);
  1019.  
  1020.         /* look up the path for the file */
  1021.         fspec = flook(fname, TRUE);
  1022.  
  1023.         /* if it isn't around */
  1024.         if (fspec == NULL) {
  1025.                 /* complain if we are interactive */
  1026.                 if (clexec == FALSE)
  1027.                         mlwrite(TEXT214, fname);
  1028. /*                              "%%No such file as %s" */
  1029.                 return(FALSE);
  1030.         }
  1031.  
  1032.         /* otherwise, execute it */
  1033.         while (n-- > 0)
  1034.                 if ((status=dofile(fspec)) != TRUE)
  1035.                         return(status);
  1036.  
  1037.         return(TRUE);
  1038. }
  1039.  
  1040. /*      dofile: yank a file into a buffer and execute it
  1041.                 if there are no errors, delete the buffer on exit */
  1042.  
  1043. PASCAL NEAR dofile(fname)
  1044.  
  1045. char *fname;    /* file name to execute */
  1046.  
  1047. {
  1048.         register BUFFER *bp;    /* buffer to place file to exeute */
  1049.         register BUFFER *cb;    /* temp to hold current buf while we read */
  1050.         register int status;    /* results of various calls */
  1051.         char bname[NBUFN];      /* name of buffer */
  1052.  
  1053.         makename(bname, fname);         /* derive the name of the buffer */
  1054.         unqname(bname);                 /* make sure we don't stomp things */
  1055.         if ((bp = bfind(bname, TRUE, 0)) == NULL) /* get the needed buffer */
  1056.                 return(FALSE);
  1057.  
  1058.         bp->b_mode = MDVIEW;    /* mark the buffer as read only */
  1059.         cb = curbp;             /* save the old buffer */
  1060.         curbp = bp;             /* make this one current */
  1061.         /* and try to read in the file to execute */
  1062.         if ((status = readin(fname, FALSE)) != TRUE) {
  1063.                 curbp = cb;     /* restore the current buffer */
  1064.                 return(status);
  1065.         }
  1066.  
  1067.         /* go execute it! */
  1068.         curbp = cb;             /* restore the current buffer */
  1069.         if ((status = dobuf(bp)) != TRUE)
  1070.                 return(status);
  1071.  
  1072.         /* if not displayed, remove the now unneeded buffer and exit */
  1073.         if (bp->b_nwnd == 0)
  1074.                 zotbuf(bp);
  1075.         return(TRUE);
  1076. }
  1077.  
  1078. /*      cbuf:   Execute the contents of a numbered buffer       */
  1079.  
  1080. PASCAL NEAR cbuf(f, n, bufnum)
  1081.  
  1082. int f, n;       /* default flag and numeric arg */
  1083. int bufnum;     /* number of buffer to execute */
  1084.  
  1085. {
  1086.         register BUFFER *bp;            /* ptr to buffer to execute */
  1087.         register int status;            /* status return */
  1088.         static char bufname[] = "[Macro xx]";
  1089.  
  1090.         /* make the buffer name */
  1091.         bufname[7] = '0' + (bufnum / 10);
  1092.         bufname[8] = '0' + (bufnum % 10);
  1093.  
  1094.         /* find the pointer to that buffer */
  1095.         if ((bp=bfind(bufname, FALSE, 0)) == NULL) {
  1096.                 mlwrite(TEXT130);
  1097. /*                      "Macro not defined" */
  1098.                 return(FALSE);
  1099.         }
  1100.  
  1101.         /* and now execute it as asked */
  1102.         while (n-- > 0)
  1103.                 if ((status = dobuf(bp)) != TRUE)
  1104.                         return(status);
  1105.         return(TRUE);
  1106. }
  1107.  
  1108. PASCAL NEAR cbuf1(f, n)
  1109.  
  1110. {
  1111.         return(cbuf(f, n, 1));
  1112. }
  1113.  
  1114. PASCAL NEAR cbuf2(f, n)
  1115.  
  1116. {
  1117.         return(cbuf(f, n, 2));
  1118. }
  1119.  
  1120. PASCAL NEAR cbuf3(f, n)
  1121.  
  1122. {
  1123.         return(cbuf(f, n, 3));
  1124. }
  1125.  
  1126. PASCAL NEAR cbuf4(f, n)
  1127.  
  1128. {
  1129.         return(cbuf(f, n, 4));
  1130. }
  1131.  
  1132. PASCAL NEAR cbuf5(f, n)
  1133.  
  1134. {
  1135.         return(cbuf(f, n, 5));
  1136. }
  1137.  
  1138. PASCAL NEAR cbuf6(f, n)
  1139.  
  1140. {
  1141.         return(cbuf(f, n, 6));
  1142. }
  1143.  
  1144. PASCAL NEAR cbuf7(f, n)
  1145.  
  1146. {
  1147.         return(cbuf(f, n, 7));
  1148. }
  1149.  
  1150. PASCAL NEAR cbuf8(f, n)
  1151.  
  1152. {
  1153.         return(cbuf(f, n, 8));
  1154. }
  1155.  
  1156. PASCAL NEAR cbuf9(f, n)
  1157.  
  1158. {
  1159.         return(cbuf(f, n, 9));
  1160. }
  1161.  
  1162. PASCAL NEAR cbuf10(f, n)
  1163.  
  1164. {
  1165.         return(cbuf(f, n, 10));
  1166. }
  1167.  
  1168. PASCAL NEAR cbuf11(f, n)
  1169.  
  1170. {
  1171.         return(cbuf(f, n, 11));
  1172. }
  1173.  
  1174. PASCAL NEAR cbuf12(f, n)
  1175.  
  1176. {
  1177.         return(cbuf(f, n, 12));
  1178. }
  1179.  
  1180. PASCAL NEAR cbuf13(f, n)
  1181.  
  1182. {
  1183.         return(cbuf(f, n, 13));
  1184. }
  1185.  
  1186. PASCAL NEAR cbuf14(f, n)
  1187.  
  1188. {
  1189.         return(cbuf(f, n, 14));
  1190. }
  1191.  
  1192. PASCAL NEAR cbuf15(f, n)
  1193.  
  1194. {
  1195.         return(cbuf(f, n, 15));
  1196. }
  1197.  
  1198. PASCAL NEAR cbuf16(f, n)
  1199.  
  1200. {
  1201.         return(cbuf(f, n, 16));
  1202. }
  1203.  
  1204. PASCAL NEAR cbuf17(f, n)
  1205.  
  1206. {
  1207.         return(cbuf(f, n, 17));
  1208. }
  1209.  
  1210. PASCAL NEAR cbuf18(f, n)
  1211.  
  1212. {
  1213.         return(cbuf(f, n, 18));
  1214. }
  1215.  
  1216. PASCAL NEAR cbuf19(f, n)
  1217.  
  1218. {
  1219.         return(cbuf(f, n, 19));
  1220. }
  1221.  
  1222. PASCAL NEAR cbuf20(f, n)
  1223.  
  1224. {
  1225.         return(cbuf(f, n, 20));
  1226. }
  1227.  
  1228. PASCAL NEAR cbuf21(f, n)
  1229.  
  1230. {
  1231.         return(cbuf(f, n, 21));
  1232. }
  1233.  
  1234. PASCAL NEAR cbuf22(f, n)
  1235.  
  1236. {
  1237.         return(cbuf(f, n, 22));
  1238. }
  1239.  
  1240. PASCAL NEAR cbuf23(f, n)
  1241.  
  1242. {
  1243.         return(cbuf(f, n, 23));
  1244. }
  1245.  
  1246. PASCAL NEAR cbuf24(f, n)
  1247.  
  1248. {
  1249.         return(cbuf(f, n, 24));
  1250. }
  1251.  
  1252. PASCAL NEAR cbuf25(f, n)
  1253.  
  1254. {
  1255.         return(cbuf(f, n, 25));
  1256. }
  1257.  
  1258. PASCAL NEAR cbuf26(f, n)
  1259.  
  1260. {
  1261.         return(cbuf(f, n, 26));
  1262. }
  1263.  
  1264. PASCAL NEAR cbuf27(f, n)
  1265.  
  1266. {
  1267.         return(cbuf(f, n, 27));
  1268. }
  1269.  
  1270. PASCAL NEAR cbuf28(f, n)
  1271.  
  1272. {
  1273.         return(cbuf(f, n, 28));
  1274. }
  1275.  
  1276. PASCAL NEAR cbuf29(f, n)
  1277.  
  1278. {
  1279.         return(cbuf(f, n, 29));
  1280. }
  1281.  
  1282. PASCAL NEAR cbuf30(f, n)
  1283.  
  1284. {
  1285.         return(cbuf(f, n, 30));
  1286. }
  1287.  
  1288. PASCAL NEAR cbuf31(f, n)
  1289.  
  1290. {
  1291.         return(cbuf(f, n, 31));
  1292. }
  1293.  
  1294. PASCAL NEAR cbuf32(f, n)
  1295.  
  1296. {
  1297.         return(cbuf(f, n, 32));
  1298. }
  1299.  
  1300. PASCAL NEAR cbuf33(f, n)
  1301.  
  1302. {
  1303.         return(cbuf(f, n, 33));
  1304. }
  1305.  
  1306. PASCAL NEAR cbuf34(f, n)
  1307.  
  1308. {
  1309.         return(cbuf(f, n, 34));
  1310. }
  1311.  
  1312. PASCAL NEAR cbuf35(f, n)
  1313.  
  1314. {
  1315.         return(cbuf(f, n, 35));
  1316. }
  1317.  
  1318. PASCAL NEAR cbuf36(f, n)
  1319.  
  1320. {
  1321.         return(cbuf(f, n, 36));
  1322. }
  1323.  
  1324. PASCAL NEAR cbuf37(f, n)
  1325.  
  1326. {
  1327.         return(cbuf(f, n, 37));
  1328. }
  1329.  
  1330. PASCAL NEAR cbuf38(f, n)
  1331.  
  1332. {
  1333.         return(cbuf(f, n, 38));
  1334. }
  1335.  
  1336. PASCAL NEAR cbuf39(f, n)
  1337.  
  1338. {
  1339.         return(cbuf(f, n, 39));
  1340. }
  1341.  
  1342. PASCAL NEAR cbuf40(f, n)
  1343.  
  1344. {
  1345.         return(cbuf(f, n, 40));
  1346. }
  1347.  
  1348.  
  1349.